import Watcher from './watcher.js';
export default class Compiler {
    constructor(context) {
        this.$el = document.querySelector(context.$el);
        this.$data = context.$data;
        this.context = context;
        // 将dom节点转换成虚拟文档片段   
        this.$fragment = this.nodeToFragment(this.$el);
        // 编译虚拟文档片段
        this.compiler(this.$fragment);
        // 将虚拟文档片段挂载到dom树上
        this.$el.appendChild(this.$fragment);
    }

    /**
     * 将dom节点转换成虚拟文档片段
     * @param {*} node 
     */
    nodeToFragment(node) {
        // 创建一个虚拟文档片段(对其进行操作不会触发dom回流)
        let fragment = document.createDocumentFragment();
        // 将页面中元素节点添加到虚拟文档片段上
        node.childNodes.forEach(child => {
            // 元素节点和非空文本节点, 都需要追加到虚拟文档片段中
            if (child.nodeType === 3 && child.textContent.trim() !== '' || child.nodeType === 1) {
                fragment.appendChild(child);
            }
        });
        // 将虚拟文档片返回
        return fragment;
    }

    /**
     * 执行模板编译
     * @param {*} node 
     */
    compiler(node) {
        // 通过循环遍历, 执行正则表达式
        node.childNodes.forEach(child => {
            // 元素节点
            if (child.nodeType === 1) {
                this.compilerElementNode(child);
            } else if (child.nodeType === 3) {
                // 文本节点
                this.compilerTextNode(child);
            }
        });
    }

    /**
     * 编辑元素节点
     * @param {} node 
     */
    compilerElementNode(node) {
        const that = this;
        let attrs = [...node.attributes];
        // 1-编译指令
        attrs.forEach(attr => {
            let {
                name: attrName,
                value: attrValue
            } = attr;
            let directName = attrName.slice(2);

            switch (directName) {
                case 'text':
                    new Watcher(attrValue, this.context, (newValue) => {
                        node.textContent = newValue;
                    });
                    break;
                case 'model':
                    new Watcher(attrValue, this.context, (newValue) => {
                        node.value = newValue;
                    });
                    // 注册input事件, 收集用户输入
                    node.addEventListener('input', (e) => {
                        // 将用户输入内容同步到作用域对象上
                        that.context[attrValue] = e.target.value;
                    });
                    break;

            }
        });
        // 2-编译方法
        // 3-递归执行文本节点编译
        this.compilerTextNode(node);
    }


    /**
     * 编译文本内容
     * @param {} node 
     */
    compilerTextNode(node) {
        // 匹配插值表达式的正则表达式
        const reg = /\{\{(.+?)\}\}/g;
        // 执行模板编译
        const pieces = node.textContent.split(reg);
        const matches = node.textContent.match(reg);
        let tokens = [];
        pieces.forEach(item => {
            if (matches && matches.indexOf(`{{${item}}}`) !== -1) {
                tokens.push('(' + item + ')');
            } else {
                tokens.push('`' + item + '`');
            }
        });
        let expression = tokens.join('+');
        new Watcher(expression, this.context, value => {
            // 更新节点内容
            node.textContent = value;
        });
    }

}